package util

import (
	"context"
	"fmt"
	"github.com/PuerkitoBio/goquery"
	"github.com/chromedp/cdproto/cdp"
	"github.com/chromedp/cdproto/network"
	"github.com/chromedp/chromedp"
	"log"
	entity2 "mp3/entity"
	"strings"
	"time"
)

const (
	Sleep_Value              = 30 * time.Second
	Default_Sleep_Value      = 30
	Default_Sleep_Value_HTTP = 600 * time.Second
	DOWNLOAD_SLEEP_VALUE     = 300
	PAGECOUNT                = 100000
	titleLength              = 6
)

func ChoosePlayList(configEntity entity2.DownloadEntity, url string, index int, firstPage bool, allocCtx context.Context) (entity2.ResponseEntity, []entity2.PlayListEntity, int) {
	responseEntity, _, _ := switchPlayList(url, entity2.DownloadEntity{}, allocCtx)
	flag := false
	if firstPage {
		responseEntity, flag = thePage(configEntity, responseEntity, allocCtx)
		if flag {
			index = configEntity.StartPageIndex - 1
			if index < 0 {
				index = 0
			}
		}

	}
	playList := playList(responseEntity.Document, configEntity, index)

	return responseEntity, playList, index
}

func thePage(configEntity entity2.DownloadEntity, responseEntity entity2.ResponseEntity, allocCtx context.Context) (entity2.ResponseEntity, bool) {
	if IsEmpty(configEntity.PageTag) || 1 > configEntity.StartPageIndex {
		return responseEntity, false
	}

	var options []*goquery.Selection

	if IsEmpty(configEntity.PageOfParentTag) {
		responseEntity.Document.Find(configEntity.PageTag).Each(func(i int, pageTag *goquery.Selection) {
			options = append(options, pageTag)
		})
	} else {
		responseEntity.Document.Find(configEntity.PageOfParentTag).Each(func(i int, selection *goquery.Selection) {
			selection.Find(configEntity.PageTag).Each(func(j int, pageTag *goquery.Selection) {
				options = append(options, pageTag)
			})
		})
	}

	length := len(options)
	if configEntity.StartPageIndex > length {
		return responseEntity, false
	}

	op := options[configEntity.StartPageIndex-1]
	url, _ := op.Attr(configEntity.PageTagAttr)
	if IsEmpty(url) {
		return responseEntity, false
	}
	url = SwitchURL(url, configEntity.BaseURL)
	responseEntity, _, _ = switchPlayList(url, configEntity, allocCtx)
	return responseEntity, true
}

/*
下载页面并转换为goquery对象
*/
func switchPlayList(url string, config entity2.DownloadEntity, allocCtx context.Context) (entity2.ResponseEntity, []*cdp.Node, string) {

	//defer cancel()

	cookieMap := make(map[string]string)

	var bodyStr string
	var nodes []*cdp.Node
	var audioURL string

	bodyStr, nodes = switchChromedp(allocCtx, url, cookieMap)

	body, err := goquery.NewDocumentFromReader(strings.NewReader(bodyStr))
	if nil != err {
		log.Println("error:", err)
	}

	return entity2.ResponseEntity{Document: body, Cookies: cookieMap, Html: bodyStr}, nodes, audioURL
}

func switchChromedp(allocCtx context.Context, url string, cookieMap map[string]string) (string, []*cdp.Node) {
	var bodyStr string
	var nodes []*cdp.Node

	allocCtx, cancel := CreateAllocCtx()
	ctx, cancel1 := chromedp.NewContext(allocCtx)
	defer cancel1()
	defer cancel()

	err := chromedp.Run(ctx,
		chromedp.Navigate(url),
		chromedp.Sleep(Sleep_Value),
		chromedp.OuterHTML(`body`, &bodyStr, chromedp.ByQuery),
		chromedp.ActionFunc(func(ctx context.Context) error {

			cookes, _ := network.GetCookies().Do(ctx)
			for _, v := range cookes {
				cookieMap[v.Name] = v.Value
			}
			return nil
		}),
	)

	if nil != err {
		log.Println("request error,,", err)
	}
	return bodyStr, nodes
}

/**获取列表*/
func playList(body *goquery.Document, configEntity entity2.DownloadEntity, pageIndex int) []entity2.PlayListEntity {
	var playListEntities []entity2.PlayListEntity
	var startTitle = FormatTitle("", pageIndex)
	body.Find(configEntity.PlayListTag).Each(func(i int, selection *goquery.Selection) {
		titleIndex := 0
		selection.Find(configEntity.PlayListChildTag).Each(func(index int, node *goquery.Selection) {
			var src, _ = node.Attr(configEntity.PlayListChildURLAttName)
			src = SwitchURL(src, configEntity.BaseURL)

			title := startTitle + SwitchTitle(configEntity, node, titleIndex)
			entity := entity2.PlayListEntity{Url: src}

			entity.TitleNames = append(entity.TitleNames, title)
			if !SwitchFileExsts(entity, configEntity) {
				playListEntities = append(playListEntities, entity)
			}

			titleIndex++
		})
	})
	return playListEntities
}

func playClick(body *goquery.Document, configEntity entity2.DownloadEntity) string {

	url := ""
	body.Find(configEntity.NextClickParentTag).Each(func(i int, selection *goquery.Selection) {
		if IsEmpty(url) {
			selection.Find(configEntity.NextClickTag).Each(func(index int, node *goquery.Selection) {
				if IsEmpty(url) {
					var src, _ = node.Attr(configEntity.NextClickTagHref)
					srcLen := len(src)
					length := len(strings.Replace(src, "javascript:void(0)", "", 1))
					if IsNotEmpty(src) && srcLen == length {
						url = SwitchURL(src, configEntity.BaseURL)
					}
				}
			})
		}

	})
	return url
}

func NextPage(body *goquery.Document, configEntity entity2.DownloadEntity, index int) string {
	if IsNotEmpty(configEntity.NextURL) {
		return fmt.Sprintf(configEntity.NextURL, index)
	}
	url := ""
	body.Find(configEntity.NextTag).Each(func(i int, selection *goquery.Selection) {

		if IsNotEmpty(url) {
			return
		}
		log.Println(configEntity.FileName, "--->NextTag:", configEntity.NextTag, "-->", i, "-->", index)
		selection.Find(configEntity.NextChildTag).Each(func(index int, node *goquery.Selection) {
			if IsNotEmpty(url) {
				return
			}
			log.Println(configEntity.FileName, "--->NextChildTag:", configEntity.NextChildTag, index)

			url, _ = node.Attr(configEntity.NextChildHref)
		})
	})

	return SwitchURL(url, configEntity.BaseURL)
}

func SwitchURL(src string, baseURL string) string {
	if IsEmpty(src) {
		return src
	}
	if !ExistStr(src, baseURL) {
		src = baseURL + src
	}
	return src
}

func SwitchTitle(configEntity entity2.DownloadEntity, node *goquery.Selection, titleIndex int) string {
	var title string

	if IsEmpty(configEntity.PlayListChildURLTitleAttName) {
		title = node.Text()
	} else {
		title, _ = node.Attr(configEntity.PlayListChildURLTitleAttName)
	}
	return FormatTitle(title, titleIndex+1)
}
